home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / VIEW.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-18  |  7.4 KB  |  295 lines

  1. /* Random access file viewer. PC specific */
  2.  
  3. #include "global.h"
  4. #include "commands.h"
  5. #include "session.h"
  6. #ifdef MSDOS
  7. #include <conio.h>
  8. #else
  9. #include "socket.h"
  10. #endif
  11.  
  12. #if !defined(_lint)
  13. static char rcsid[] OPTIONAL = "$Id: view.c,v 1.19 1997/08/19 01:19:22 root Exp root $";
  14. #endif
  15.  
  16.  
  17. static long lineseek (FILE *fp,long offset,int nlines,int width);
  18. static void view (int s, void *p1, void*p2);
  19. extern char NoRead[];
  20. extern char readmeFile[];
  21. #ifdef UNIX
  22. extern int Numrows, Numcols;
  23. #endif
  24.  
  25.  
  26. int
  27. doview(argc,argv,p)
  28. int argc OPTIONAL;
  29. char *argv[];
  30. void *p OPTIONAL;
  31. {
  32. char fname[256];
  33. FILE *fp;
  34.  
  35.     /*allow only keyboard users to access the view command*/
  36.     if (Curproc->input != Command->input) {
  37.         tputs ("The 'view' command can only be executed from the command session.\nTry the 'more' command, instead!\n\n");
  38.         return 0;
  39.     }
  40.  
  41.     strncpy (fname, make_fname (Command->curdirs->dir,argv[1]), 256);
  42.     if((fp = fopen (fname, READ_TEXT)) == NULLFILE)    {
  43.         tprintf (NoRead, fname, SYS_ERRLIST(errno));
  44.         return 1;
  45.     }
  46.     (void) newproc ("view", 512, view, 0, (void *)fp, (argv[1] == readmeFile) ? (void *) strdup("Reviewing the new features file") : (void *) strdup(argv[1]),(argv[1] == readmeFile) ? 0 : 2);
  47.     return 0;    
  48. }
  49.  
  50.  
  51. /* Random-access file display program. Used both to read local
  52.  * files with the "view" command, and by the FTP client to view
  53.  * directory listings, temporary copies of read files, etc.
  54.  */
  55. static void
  56. view (s, p1, p2)
  57. int s;        /* If non-zero, poll interval for a changing file */
  58. void *p1;    /* Open file pointer to read from */
  59. void *p2;    /* If non-null, name to give to session. We free it */
  60. {
  61. struct session *sp;
  62. FILE *fp;
  63. char *name;
  64. int c;
  65. long offset = 0;
  66. int row,col;
  67. int cols;
  68. int rows;
  69. int32 polldelay = 0;
  70. #ifndef UNIX
  71. struct text_info text_info;
  72.  
  73.     gettextinfo (&text_info);
  74.     cols = text_info.screenwidth;
  75.     rows = text_info.screenheight-1;    /* Allow for status line */
  76. #else
  77.     cols = Numcols;
  78.     rows = Numrows;
  79. #endif
  80.  
  81.     fp = (FILE *)p1;
  82.     name = (char *)p2;
  83.  
  84.     if ((sp = newsession (name, VIEW, 0)) == NULLSESSION)
  85.         return;
  86.  
  87.     if (s != 0)
  88.         polldelay = s;
  89.     /* Put tty into raw mode so single-char responses will work */
  90.     sp->ttystate.echo = sp->ttystate.edit = 0;
  91.     for ( ; ; )    {
  92.         fseek (fp, offset, SEEK_SET);
  93.         clrscr ();
  94.         /* Display a screen's worth of data, keeping track of
  95.          * cursor location so we know when the screen is full
  96.          */
  97.         col = row = 0;
  98.         while ((c = getc (fp)), c != EOF)    {
  99.             switch (c)    {
  100.                 case '\n':    row++;
  101.                         col = 0;
  102.                         break;
  103.                 case '\t':    if (col < cols - 8)
  104.                             col = (col + 8) & ~7;
  105.                         break;
  106.                 default:    col++;
  107.                         break;
  108.             }
  109.             if (col >= cols)    {
  110.                 /* Virtual newline caused by wraparound */
  111.                 col = 0;
  112.                 row++;
  113.             }
  114.             if (row >= rows)
  115.                 break;    /* Screen now full */
  116.             tputc ((unsigned char)c);
  117.         }
  118.         tflush();
  119.         /* If we hit the end of the file and the file may be
  120.          * growing, then set an alarm to time out the getchar()
  121.          */
  122.         do {
  123.             if (feof(fp) && polldelay != 0)
  124.                 kalarm (polldelay);
  125.             c = recvchar (Curproc->input);
  126.             kalarm (0L);        /* Cancel alarm */
  127.             if (c != EOF || errno != EALARM)
  128.                 break;        /* User hit key */
  129.             /* Alarm timeout; see if more data arrived by
  130.              * clearing the EOF flag, trying to read
  131.              * another byte, and then testing EOF again
  132.              */
  133.             clearerr (fp);
  134.             (void)getc (fp);
  135.             c = ' ';    /* Simulate a no-op keypress */
  136.         } while (feof (fp));
  137.         switch (c)    {
  138.             case 'h':    /* Home */
  139.             case 'H':
  140.             case '<':    /* For emacs users */
  141.                 offset = 0;
  142.                 break;
  143.             case 'e':    /* End */
  144.             case '>':    /* For emacs users */
  145.                 fseek (fp, 0L, SEEK_END);
  146.                 offset = lineseek (fp, ftell (fp), -rows, cols);
  147.                 break;
  148.             case CTLD:    /* Down one half screen (for VI users) */
  149.                 if (!feof (fp))
  150.                     offset = lineseek (fp, offset, rows / 2, cols);
  151.                 break;
  152.             case CTLU:    /* Up one half screen (for VI users) */
  153.                 offset = lineseek (fp, offset, -rows / 2, cols);
  154.                 break;
  155.             case 'd':    /* down line */
  156.             case CTLN:    /* For emacs users */
  157.             case 'j':    /* For vi users */
  158.                 if (!feof (fp))
  159.                     offset = lineseek (fp, offset, 1, cols);
  160.                 break;
  161.             case 'D':    /* Down page */
  162.             case CTLV:    /* For emacs users */
  163.                 if (!feof (fp))
  164.                     offset = lineseek (fp, offset, rows, cols);
  165.                 break;
  166.             case 'u':    /* up line */
  167.             case CTLP:    /* for emacs users */
  168.             case 'k':    /* for vi users */
  169.                 offset = lineseek (fp, offset, -1, cols);
  170.                 break;
  171.             case 'U':    /* Up page */
  172.             case 'v':    /* for emacs users */
  173.                 offset = lineseek (fp, offset, -rows, cols);
  174.                 break;
  175.             case CTLC:
  176.             case 'q':
  177.             case 'Q':
  178.             case ESC:
  179.                 goto done;
  180.             default:
  181.                 break;    /* Redisplay screen */
  182.         }
  183.     }
  184. done:    (void) fclose (fp);
  185.     freesession (sp);
  186. }
  187.  
  188.  
  189. /* Given a starting offset into an open file stream, scan forwards
  190.  * or backwards the specified number of lines and return a pointer to the
  191.  * new offset.
  192.  */
  193. static long
  194. lineseek(fp,start,nlines,width)
  195. FILE *fp;    /* Open file stream */
  196. long start;    /* Offset to start searching backwards from */
  197. int nlines;    /* Number of lines to move forward (+) or back (-) */
  198. int width;    /* Screen width (max line size) */
  199. {
  200. long offset;
  201. long *pointers;
  202. int col = 0;
  203. int c;
  204. int newlines = 0;
  205.  
  206.     if (nlines == 0)
  207.         return start;    /* Nothing to do */
  208.  
  209.     if (nlines > 0)    {    /* Look forward requested # of lines */
  210.         fseek (fp, start, SEEK_SET);
  211.         col = 0;
  212.         while ((c = getc (fp)), c != EOF)    {
  213.             switch (c)    {
  214.                 case '\n':    newlines++;
  215.                         col = 0;
  216.                         break;
  217.                 case '\t':    if (col < width - 8)
  218.                             col = (col + 8) & ~7;
  219.                         break;
  220.                 default:    col++;
  221.                         break;
  222.             }
  223.             if (col >= width)    {
  224.                 /* Virtual newline caused by wraparound */
  225.                 col = 0;
  226.                 newlines++;
  227.             }
  228.             if (newlines >= nlines)
  229.                 break;    /* Found requested count */
  230.         }
  231.         return (ftell (fp));    /* Could be EOF */
  232.     }
  233.     /* Backwards scan (the hardest)
  234.      * Start back up at most (width + 2) chars/line from the start.
  235.      * This handles full lines followed by expanded newline
  236.      * sequences
  237.      */
  238.     nlines = -nlines;
  239.     offset = (width + 2) * (nlines + 1);
  240.     if (offset > start)
  241.         offset = 0;    /* Go to the start of the file */
  242.     else
  243.         offset = start - offset;
  244.     fseek (fp, offset, SEEK_SET);
  245.  
  246.     /* Keep a circular list of the last 'nlines' worth of offsets to
  247.      * each line, starting with the first
  248.      */
  249.     if (nlines == 0)
  250.         return offset;
  251.     pointers = (int32 *) callocw (sizeof(long), (unsigned) nlines);
  252.     if (pointers == (int32*) 0)
  253.         return start;        /* shouldn't ever happen */
  254.     pointers[newlines++ % nlines] = offset;
  255.  
  256.     /* Now count newlines up but not including the original
  257.      * starting point
  258.      */
  259.     col = 0;
  260.     for ( ; ; )    {
  261.         c = getc (fp);
  262.         switch (c)    {
  263.             case EOF:    goto done;
  264.             case '\n':    col = 0;
  265.                     offset = ftell (fp);
  266.                     if (offset >= start)
  267.                         goto done;
  268.                     pointers[newlines++ % nlines] = offset;
  269.                     break;
  270.             case '\t':    if (col < width - 8)
  271.                         col = (col + 8) & ~7;
  272.                     break;
  273.             default:    col++;
  274.                     break;
  275.         }
  276.         if (col >= width)    {
  277.             /* Virtual newline caused by wraparound */
  278.             col = 0;
  279.             offset = ftell (fp);
  280.             if (offset >= start)
  281.                 goto done;
  282.             pointers[newlines++ % nlines] = offset;
  283.         }
  284.     }
  285.  
  286. done:
  287.     if (newlines >= nlines)    /* Select offset pointer nlines back */
  288.         offset = pointers[newlines % nlines];
  289.     else     /* The specified number of newlines wasn't seen, so go to the start of the file */
  290.         offset = 0;
  291.  
  292.     free (pointers);
  293.     return (offset);
  294. }
  295.